Skip to main content

Board

OLEM is provided with 2 types of boards : the first type is made up of squares and the second one is made up of triangles forming hexagonal shapes.

Untitled

Untitled

To help with using those boards in game, the board module provides the data structures and API that we use for our own games. There is also a level editor that can be used to create levels through a GUI.

To introduce the board API and data structures, we will start with the smallest units and move our way up to the entire board.

The boards and their components

Elements

An element is used to represent something that resides on the board. It could be:

  • OLEM
  • A physical object (game piece), such as a wall, a miniature, resources
  • Data tied to a specific position that won’t be seen by users but can be used by the game code. For example, in Guardian & Thieves, possible treasure spawning positions are saved in the level but actual treasures are generated by code when loading the level.

Data structure

An element is an object that has:

  • A type stored as a string
  • Customizable parameters, those have :
    • a string name (key)
    • a string value associated to that string (think Hashmap / JSON)

API

"""
Class constructor

:param type_string: string type
"""
Element(type_string)

"""
Returns the element's type param. Gives the same output as get_param("type").
"""
get_type()

"""
Get the value of the given parameter

:param param_name: string name of the parameter to be retrieved

Returns the associated string value
"""
get_param(param_name)

"""
Set the value of a parameter. If a parameter with the same name already
exists, value is overriden, otherwise it is created.

:param param_name: string name of the parameter
:param value: string value associated to the name
"""
set_param(param_name, value)

Containers

To place elements on the board, they are stored in containers. There are 3 types of containers :

  • Node
  • Cell
  • Border

Those types are explained in more details in the Tiles section below

Data structure

A container is a list of elements.

API

"""
Check if the container contains at least one element of
a specific type

:param type: string type to check

Returns a boolean
"""
has_element_type(type)

"""
Add an element to the container.

:param element: Element object to be stored in container
"""
add_element(element)

"""
Remove element from container. This element is NOT destroyed.

:param element: element obj to be removed from container
"""
remove_element(element)

"""
Remove all elements from the container.
"""
clear_elements()

"""
Returns the list of elements in the container.
"""
get_elements()

"""
Get the first element of the specified type.

:param string_type: string type to search for

Returns an Element object
"""
get_element_by_type(string_type)

"""
Get all elements of the specified type.

:param string_type: string type to search for

Returns a list of Element objects
"""
get_elements_by_type(string_type)

"""
Checks if the container has elements stored.

Returns a boolean
"""
is_empty()

Tiles

Tiles are the basic units that are repeated in order to create a board. They look a bit different depending on the type of board but they still follow a common structure created using the containers introduced above :

  • Nodes are positions between cells on the board, where OLEM can be (other elements can be placed there). There is only one node per tile
  • Cells are, well, traditional cells on a board game
  • Borders are the areas between cells, where, for example, walls can be placed

Data structure

A tile contains :

  • its (x, y) coordinates on the board
  • One node
  • An array of cells
  • An array of borders

Square tile

Untitled

For the board made up of squares, a tile is defined as follow:

Diagramme sans nom.drawio(1).png

with:

  • 1, the node
  • 2, the cell (here there is only one)
  • 3, the top border
  • 4, the left border

Triangular tiles

Untitled

hex_tile.png

with:

  • 1 the node
  • 2 the cells
  • 3 the borders

API

"""
Get the border of a tile

:param id: in a squareboard 0 is the top horizontal border, 1 is the left vertical border
Returns a container
"""
get_border(id)

"""
Get the cell of a tile

Returns a container
"""
get_cell()

"""
Get the node of a tile

Returns a container
"""
get_node()

"""
Get x coordinate of a tile
"""
get_x()

"""
Get y coordinate of a tile
"""
get_y()

"""
Checks if the cells, node and borders are all empty

Returns a boolean
"""
is_empty()

Board

We define a board as an object that has:

  • a number of columns
  • a number of rows
  • tiles of a specific dimensions (width and height, both in mm)
  • a name
  • an array of customizable parameters
  • an array of tiles

By positioning several tiles next to each other, we end up with this structure (screenshoted from level editor):

booard_coord.svg

NOTE: With the structure we use some of the containers are actually outside the board as some nodes are on the edge of the board

"""
Create an empty squareboard
NB: see genericboard.load_board() to load a board created with the level editor

:param rows: number of rows
:param columns: number of columns
:param tile_width: width of a tile in mm
:param tile_height: height of a tile in mm

Returns a squareboard object
"""
squareboard(rows, columns, tile_width, tile_height)

"""
Displays all tiles of the board with a single digit per tile.
0 indicates an empty tile, 1 indicates not empty
"""
print()

"""
Destroy the board object
NB: Right now this has to be called manually to avoid memory leak.
We are looking for a proper way to automatically destroy it as this is
an issue when the script crashes.
"""
__del__()

"""
Get the number of rows in the board

Returns an int
"""
get_row_count()

"""
Get the number of columns in the board

Returns an int
"""
get_column_count()

"""
Check if a position is valid on the board
:param x: x coordinate on the board
:param y: y coordinate on the board

Return a boolean
"""
is_position_within_board(x, y)

"""
Get tile from its position
:param x: x coordinate on the board
:param y: y coordinate on the board

Return a tile object or None if tile does not exists
"""
get_tile(x, y)

"""
Get level name

Returns a string
"""
get_name()

"""
Get the value of the given parameter

:param param_name: string name of the parameter to be retrieved

Returns the associated string value
"""
get_param(param_name)

"""
Set the value of a parameter. If a parameter with the same name already
exists, value is overriden, otherwise it is created.

:param param_name: string name of the parameter
:param value: string value associated to the name
"""
set_param(param_name, value)

########################################
# Not implemetend or not tested

get_tile_dimension
get_tiles
get_neighbor_tiles
get_border_from_tile(tile, direction)
get_border_from_position(x, y, direction)

Static functions

Those functions are not called on the objects

"""
Creates a board based on a json file generated by the level editor

:param path_to_file: path in filesystem to board

Returns a squareboard object
"""
genericboard.load_board(path_to_file)

Example

Basic

import genericboard
import olem

TYPE_START = "start"
TYPE_WALL = "wall"
TYPE_END = "end"

def find_starting_pos(b):
for y in range(b.get_row_count()):
for x in range(b.get_column_count()):
tile = b.get_tile(x, y)
node = tile.get_node()

if (node.has_element_type(TYPE_START)):
print("found start at " + str(x) + " " + str(y))
return (x, y)

def is_node_walkable(board, x, y):
board_edge = False
if not board.is_position_within_board(x, y):
board_edge = True
if not board.is_position_within_board(x - 1, y):
board_edge = True
if not board.is_position_within_board(x, y - 1):
board_edge = True

if board_edge:
print("board edge is not walkable")
return False

has_wall = False
tile = board.get_tile(x, y)
if tile.get_node().has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(0).has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(1).has_element_type(TYPE_WALL):
has_wall = True

if(has_wall):
print("target tile has walls")
return False

print("looking left")
tile = board.get_tile(x - 1, y)
if tile.get_border(0).has_element_type(TYPE_WALL):
return False

print("looking up")
tile = board.get_tile(x, y - 1)
if tile.get_border(1).has_element_type(TYPE_WALL):
return False

return True

def get_command():
msg = olem.gmsg_wait_for_message()

if msg == "up":
return (0, -1)

if msg == "down":
return (0, 1)

if msg == "left":
return (-1, 0)

if msg == "right":
return (1, 0)

return (0, 0)

def end_reached(board, current_position):
tile = board.get_tile(current_position[0], current_position[1])
return tile.get_node().has_element_type(TYPE_END)

print("Board tester")

b = genericboard.load_board("/tmp/board_tester")
b.print()

starting_position = find_starting_pos(b)
current_position = starting_position

while not end_reached(b, current_position):
command = get_command()
if is_node_walkable(b, current_position[0] + command[0], current_position[1] + command[1]):
current_position = (current_position[0] + command[0], current_position[1] + command[1])
print("Moved to " + str(current_position[0]) + " " + str(current_position[1]))
else:
print("Node " + str(current_position[0] + command[0]) + " " + str(current_position[1] + command[1]) + " is not walkable")

print("End reached")
b.__del__()